package com.example.gokchinesefoodmapmcdev.controller;

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.example.gokchinesefoodmapmcdev.entity.sms.SmsProperties;
import com.example.gokchinesefoodmapmcdev.entity.sys.SysUser;
import com.example.gokchinesefoodmapmcdev.filter.JWTTokenAuthenticationFilter;
import com.example.gokchinesefoodmapmcdev.handler.MyLoginSuccessHandler;
import com.example.gokchinesefoodmapmcdev.service.ClientService;
import com.example.gokchinesefoodmapmcdev.util.CacheUtils;
import com.example.gokchinesefoodmapmcdev.util.JWTUtils;
import com.example.gokchinesefoodmapmcdev.util.ResultData;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.code.kaptcha.Producer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

@RestController
public class LoginController {

    private final static Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private CacheUtils cacheUtils;

    @Autowired
    private Producer kaptchaProducer;

    @Autowired
    private SmsProperties smsProperties;

    @Autowired
    private ClientService clientService;

    @Autowired
    private MyLoginSuccessHandler myLoginSuccessHandler;

    /**
     * 使用手机短信验证码登录
     *     1. 如果未注册（数据库中没有手机号信息），则返回提示登录
     *     2. 验证码错误，则返回提示信息
     *     3. 登录成功，需要将用户数据（需要权限和用户名）查出来，存入UserDetails的实现子类User中
     */
    @PostMapping("/rest/app/authCode")
    public ResultData authCoder(@RequestParam("phone") String mobile,@RequestParam("msgcode") String msgCode,
                                HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        // 1. 验证码错误
        if(msgCode == null || !msgCode.equals(msgCode)){
            return ResultData.fail(ResultData.VERIFY_FAIL, "验证码错误");
        }

        // 2. 未注册
        SysUser sysUser = clientService.findUserByUserMobile(mobile);
        if(sysUser == null){
            return ResultData.fail(ResultData.VERIFY_FAIL, "您还未注册");
            // 注：这里返回注册
        }

        // 3. 登录成功，走自定义登录逻辑
        Authentication authentication = clientService.addUserInfoToUserDetails(sysUser);

        myLoginSuccessHandler.onAuthenticationSuccess(request, response, authentication);

        return null;
    }

    /**
     * 阿里云发送手机短信验证码api的接口
     */
    @RequestMapping("/rest/sms/sendMsg")
    public void sendMsg(@RequestBody Map<String, Object> map){
        String mobile = (String) map.get("telephone");
        /*System.out.println("=======访问验证码发送接口======");*/
        // 生成4位数字的验证码信息
        StringBuilder code = new StringBuilder();
        Random random = new Random();
        for(int i = 0; i < 4; i++){
            code.append(random.nextInt(10));
        }
        // 将验证码保存在缓存中（以用户的手机号作为key值，因为用户手机号唯一，当前用户就能取到自己的验证码）
        cacheUtils.getLocalCache().put(mobile, code.toString());
        System.out.println(code.toString());

        // 阿里云短信服务
        Config config = new Config()
                // 必填，您的 AccessKey ID
                .setAccessKeyId(smsProperties.getAccessKeyId())
                // 必填，您的 AccessKey Secret
                .setAccessKeySecret(smsProperties.getAccessKeySecret());
        // 访问的域名
        config.endpoint = smsProperties.getEndpoint();

        SendSmsRequest sendSmsRequest = new SendSmsRequest()
                .setSignName(smsProperties.getSignName())
                .setTemplateCode(smsProperties.getTemplateCode())
                .setPhoneNumbers(mobile)
                .setTemplateParam("{code:" + code + "}");
        RuntimeOptions runtime = new RuntimeOptions();
        try {
            Client client = new Client(config);
            // 发送验证码
            client.sendSmsWithOptions(sendSmsRequest, runtime);

        } catch (TeaException error) {
            logger.error(error.message);
            com.aliyun.teautil.Common.assertAsString(error.message);
        } catch (Exception _error) {
            TeaException error = new TeaException(_error.getMessage(), _error);
            logger.error(error.message);
            com.aliyun.teautil.Common.assertAsString(error.message);
        }
    }


    /**
     * 校验token
     */
    @RequestMapping("/rest/app/authStatus")
    public void authStatus(HttpServletResponse response) {
        // 4. 响应结果
        ResultData resultData = ResultData.ok(ResultData.VERIFY_SUCCESS, "验证成功");
        try {
            response.getWriter().println(new ObjectMapper().writeValueAsString(resultData));
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * 登录界面的验证码生成功能
     */
    @RequestMapping("/captcha")
    public void getCaptcha(HttpServletResponse response) {
        // 1. 生成验证码中的 文字和图片
        String text = kaptchaProducer.createText();
        BufferedImage image = kaptchaProducer.createImage(text);

        /*
            2. 将验证码文字存入缓存中，用于判断
                    在多线程的条件下，为了确保当前用户使用到的验证码是自己的，
                    可以仿照session向前端发送一个id，通过这个id得到验证码信息
         */
        String uuid = UUID.randomUUID().toString();
        cacheUtils.getLocalCache().put(uuid, text);
        Cookie cookie = new Cookie("kaptcha", uuid);
        cookie.setMaxAge(180);
        response.addCookie(cookie);

        System.out.println(text);
        System.out.println(uuid);

        // 3. 将图片输出给浏览器
        response.setContentType("image/png");
        try {
            OutputStream os = response.getOutputStream();
            // 使用ImageIO输出图片，指定图片、图片格式、输出流（注：这个输出流不用关闭。因为整个response是由SpringMVC维护，它自动会关闭。）
            ImageIO.write(image, "png", os);
        } catch (IOException e) {
            // 异常需要记录日志信息。。。
            logger.error("验证码输出失败。。。" + e.getMessage());
        }
    }

}
